package modelo.info;

import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import modelo.mapeado.Coordinate;
import modelo.mapeado.CoordinateRangeException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class OSMCodificator extends Thread {

	private String consulta;
	private ArrayList<MapNode> nodeList;
	private ArrayList<MapWay> wayList;
	private static Integer error = 0;
	
	public OSMCodificator() {
		
		nodeList = new ArrayList<MapNode>();
		wayList = new ArrayList<MapWay>();		
	}
	
	public void obtenerInfo(Double izquierda,Double abajo,Double derecha,Double arriba) {
		
		consulta = "http://api.openstreetmap.org/api/0.6/map?bbox="+izquierda+","+abajo+","+derecha+","+arriba;
		System.out.println("Consulta: "+consulta);
		Document document = getDocumentOSM();
		
		Node nodo = document.getDocumentElement();
		NodeList lista = nodo.getChildNodes();
		for (int i=0;i<lista.getLength();i++) {
			if (lista.item(i).getNodeName().equals("node")) {
				MapNode nuevo =  getNode(lista.item(i));
				if (nuevo != null)
					nodeList.add(nuevo);
			}
			else if (lista.item(i).getNodeName().equals("way")){
				MapWay nueva = getWay(lista.item(i));
				wayList.add(nueva);
			}
		}
		System.out.println("Nodos: "+nodeList.size());
		for (int i=0;i<nodeList.size();i++)
			if (!nodeList.get(i).getUtilizado())
				nodeList.remove(i);
		System.out.println("Nodos: "+nodeList.size());	
	}
	
	public Document getDocumentOSM() {
		
		URL url = null;
		Document document = null;
		try {
			url = new URL(consulta);
			URLConnection conn = url.openConnection();
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			document = builder.parse(conn.getInputStream());
		} 
		catch (Exception e) {
			System.out.println("Fallando...");
			document = getDocumentOSM();
		}
		return document;
	}
	
	public MapNode getNode(Node node) {
		
		Double id = 0.0;
		Double lat = 0.0;
		Double lon = 0.0;
		NamedNodeMap nodeMap = node.getAttributes();
		for (int i=0;i<nodeMap.getLength();i++) {
			if (nodeMap.item(i).getNodeName().equals("id"))
				id = new Double(nodeMap.item(i).getNodeValue());
			else if (nodeMap.item(i).getNodeName().equals("lat"))
				lat = new Double(nodeMap.item(i).getNodeValue());
			else if (nodeMap.item(i).getNodeName().equals("lon"))
				lon = new Double(nodeMap.item(i).getNodeValue());
		}
		Coordinate coordenada = null;
		try {
			coordenada = new Coordinate (lat,lon);
		} catch (CoordinateRangeException e) {
			e.printStackTrace();
		}
		MapNode nodo = new MapNode(id,coordenada);
		NodeList lista = node.getChildNodes();
		for (int i=0;i<lista.getLength();i++) {
			nodeMap = lista.item(i).getAttributes();
			if (nodeMap !=null) {
				Integer j=0;
				while(j<nodeMap.getLength()) {
					if (nodeMap.item(j).getNodeName().equals("k")) {
						nodo.getInfo().put(nodeMap.item(j).getNodeValue(), nodeMap.item(j+1).getNodeValue());
						j = j+1;
					}
					j = j+1;
				}
			}
		}
		return nodo;
	}
	
	public MapWay getWay(Node node) {
		
		MapWay way = new MapWay();
		NodeList lista = node.getChildNodes();
	
		for (int i=0;i<lista.getLength();i++) {
			NamedNodeMap nodeMap = lista.item(i).getAttributes();
			if (nodeMap != null) {
				Integer j=0;
				while (j<nodeMap.getLength()) {
					if (nodeMap.item(j).getNodeName().equals("ref")) {
						Double numNodo = new Double(nodeMap.item(j).getNodeValue());
						Boolean encontrado = false;
						for (int k=0;k<nodeList.size() && !encontrado;k++) {
							if (nodeList.get(k).getId().equals(numNodo)) {
								way.getNodos().add(nodeList.get(k));
								nodeList.get(k).setUtilizado(true);
								encontrado = true;
							}
						}
						if (!encontrado) {
							System.out.println("Error "+error+" en: "+numNodo);
							error++;
						}
					}
					else {
						if (nodeMap.item(j).getNodeName().equals("k")) {
							way.getDatos().put(nodeMap.item(j).getNodeValue(),nodeMap.item(j+1).getNodeValue());
							j = j+1;
						}
					}
					j = j+1;
				}
			}
		}
		return way;
	}
	
	public ArrayList<MapNode> getNodeList() {
		return nodeList;
	}

	public void setNodeList(ArrayList<MapNode> nodeList) {
		this.nodeList = nodeList;
	}

	public ArrayList<MapWay> getWayList() {
		return wayList;
	}

	public void setWayList(ArrayList<MapWay> wayList) {
		this.wayList = wayList;
	}
}
